package pso.particle;

import java.util.logging.Logger;

import evolution.problem.FitnessFunction;
import evolution.problem.OptimizationProblem;
import evolution.problem.ProblemConstraints;
import evolution.random.RandomGenerator;
import evolution.random.SFMT19937RandomGen;

public class SwarmInitializer {

	private static final Logger log = Logger.getLogger(SwarmInitializer.class
			.getCanonicalName());

	private static RandomGenerator random = new SFMT19937RandomGen();

	public static ParticleNeighborhood initializeSwarm(
			OptimizationProblem problem, int count) {
		ProblemConstraints constraints = problem.getConstraints();
		double minArg = constraints.getMinArg();
		double maxArg = constraints.getMaxArg();
		int dimensions = constraints.getDimensions();
		FitnessFunction fitnessFunction = problem.getFitnessFunction();

		Particle[] neighbours = new Particle[count];
		double[] bestPos = new double[dimensions];
		double bestVal = Double.MIN_VALUE;
		for (int i = 0; i < count; i++) {
			Particle p = generateParticle(minArg, maxArg, dimensions,
					fitnessFunction, random);
			neighbours[i] = p;
			if (p.getFitness() > bestVal) {
				bestVal = p.getFitness();
				bestPos = p.getPosition().clone();
			}
		}

		ParticleNeighborhood neighborhood = new ParticleNeighborhood(neighbours);
		neighborhood.setBestValue(bestVal);
		neighborhood.setBestPosition(bestPos);
		return neighborhood;
	}

	public static Particle generateParticle(double minPos, double maxPos,
			int dimensions, FitnessFunction fitnessFunction,
			RandomGenerator random) {
		Particle particle = new Particle();
		particle.setFitnessFunction(fitnessFunction);

		double[] coordinates = new double[dimensions];
		for (int i = 0; i < dimensions; i++) {
			coordinates[i] = ((maxPos - minPos) + minPos) * random.nextDouble();
		}
		particle.setPosition(coordinates);
		particle.setBestPosition(coordinates);

		double[] velocity = new double[dimensions];
		for (int i = 0; i < dimensions; i++) {
			velocity[i] = ((maxPos - minPos) + minPos) * random.nextDouble();
		}
		particle.setVelocity(velocity);

		// log.info("Initial position: " + Arrays.toString(coordinates));
		// log.info("Initial velocity: " + Arrays.toString(velocity));

		return particle;
	}
}
